package com.yixuan.mt.common.local.buckets;

import com.yixuan.mt.common.constant.BucketsConstant;
import com.yixuan.mt.common.entity.Bucket;
import com.yixuan.mt.common.local.objects.ObjectsIndex;

import java.io.*;

public class BucketsMeta {

    static {
        try {
            createGlobalBucketMeta();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void createGlobalBucketMeta() throws IOException {
        File file = new File(BucketsConstant.BUCKET_META_GLOBAL_FILE_PATH);
        if (!file.exists()) {
            if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) {
            }
            file.createNewFile();
        }
    }

    /**
     * 暂时这样设计（目前全局元数据文件存的只有所有桶名）
     */
    public static void addToGlobalBucketMeta(String data) throws IOException {
        // 打开文件
        File file = new File(BucketsConstant.BUCKET_META_GLOBAL_FILE_PATH);
        // 追加数据到文件
        FileOutputStream fo = new FileOutputStream(file, true);
        try (fo) {
            // 写入桶名
            fo.write(data.getBytes());
            fo.write("\n".getBytes());
        }
    }

    public static String[] getBucketListInGlobalMeta() throws IOException {
        // 读取文件的数据
        File file = new File(BucketsConstant.BUCKET_META_GLOBAL_FILE_PATH);
        // 读取文件的数据
        FileReader fr = new FileReader(file);
        try (fr) {
            BufferedReader br = new BufferedReader(fr);
            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line).append("\n");
            }
            return sb.toString().split("\n");
        }
    }

    public static void createLocalBucketMeta(String bucketName) throws IOException {
        File file = new File(BucketsConstant.BUCKET_META_PREFIX_PATH + bucketName + BucketsConstant.BUCKET_META_ALONE_FILE_SUFFIX_PATH);
        if (!file.exists()) {
            if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) {
                throw new IOException("创建文件失败");
            }
            file.createNewFile();
        }
    }

    public static void addConstantToLocalBucketMeta(String bucketName, byte data) throws IOException {
        // 打开文件
        File file = new File(BucketsConstant.BUCKET_META_PREFIX_PATH + bucketName + BucketsConstant.BUCKET_META_ALONE_FILE_SUFFIX_PATH);
        // 追加数据到文件
        FileOutputStream fo = new FileOutputStream(file, true);
        try (fo) {
            fo.write(data);
        }
    }

    public static void addIntToLocalBucketMeta(String bucketName, int data) throws IOException {
        // 打开文件
        File file = new File(BucketsConstant.BUCKET_META_PREFIX_PATH + bucketName + BucketsConstant.BUCKET_META_ALONE_FILE_SUFFIX_PATH);
        // 追加数据到文件
        FileOutputStream fo = new FileOutputStream(file, true);
        DataOutputStream dos = new DataOutputStream(fo);
        try (fo; dos) {
            dos.writeInt(data);
        }
    }

    public static void addStringToLocalBucketMeta(String bucketName, String data) throws IOException {
        File file = new File(BucketsConstant.BUCKET_META_PREFIX_PATH + bucketName + BucketsConstant.BUCKET_META_ALONE_FILE_SUFFIX_PATH);
        // 追加数据到文件
        FileOutputStream fo = new FileOutputStream(file, true);
        try (fo) {
            fo.write(data.getBytes());
        }
    }

    public static byte getConstantInLocalBucketMeta(String bucketName, String key) throws IOException {
        File file = new File(BucketsConstant.BUCKET_META_PREFIX_PATH + bucketName + BucketsConstant.BUCKET_META_ALONE_FILE_SUFFIX_PATH);
        FileInputStream fi = new FileInputStream(file);
        if (key.equals("accessPolicy")) {
            fi.skip(BucketsConstant.BUCKET_META_2_ACCESS_POLICY_POS);
        } else {
            return -1;
        }
        byte[] constant = new byte[1];
        try (fi) {
            fi.read(constant);
        }
        return constant[0];
    }

    public static int getIntInLocalBucketMeta(String bucketName, String key) throws IOException {
        File file = new File(BucketsConstant.BUCKET_META_PREFIX_PATH + bucketName + BucketsConstant.BUCKET_META_ALONE_FILE_SUFFIX_PATH);
        FileInputStream fi = new FileInputStream(file);
        DataInputStream di = new DataInputStream(fi);
        if (key.equals("objectNumber")) {
             di.skip(BucketsConstant.BUCKET_META_3_OBJECTS_NUMBER_POS);
        } else {
            return -1;
        }
        try (fi; di) {
            return di.readInt();
        }
    }

    public static String getStringInLocalBucketMeta(String bucketName, String key) throws IOException {
        File file = new File(BucketsConstant.BUCKET_META_PREFIX_PATH + bucketName + BucketsConstant.BUCKET_META_ALONE_FILE_SUFFIX_PATH);
        FileInputStream fi = new FileInputStream(file);
        int len;
        if (key.equals("createdTime")) {
            len = BucketsConstant.BUCKET_META_1_CREATED_TIME_LENGTH;
            fi.skip(BucketsConstant.BUCKET_META_1_CREATED_TIME_POS);
        } else {
            return null;
        }
        byte[] bytes = fi.readNBytes(len);
        return new String(bytes);
    }

    public static Bucket getBasicInfoInLocalBucketMeta(String bucketName) throws IOException {
        File file = new File(BucketsConstant.BUCKET_META_PREFIX_PATH + bucketName + BucketsConstant.BUCKET_META_ALONE_FILE_SUFFIX_PATH);
        FileInputStream fi = new FileInputStream(file);
        DataInputStream di = new DataInputStream(fi);
        try (fi; di) {
            Bucket bucketBasicInfo = new Bucket();
            bucketBasicInfo.setName(bucketName);
            bucketBasicInfo.setCreatedTime(new String(di.readNBytes(BucketsConstant.BUCKET_META_1_CREATED_TIME_LENGTH)));
            bucketBasicInfo.setAccessPolicy((int) di.readByte());
//            bucketBasicInfo.setObjectNumber(di.readInt());
            return bucketBasicInfo;
        }
    }

    public static void updateObjectNumberInLocalBucketMeta(String bucketName) throws IOException {
        File file = new File(BucketsConstant.BUCKET_META_PREFIX_PATH + bucketName + BucketsConstant.BUCKET_META_ALONE_FILE_SUFFIX_PATH);
        RandomAccessFile raf = new RandomAccessFile(file, "rw");
        try (raf) {
            raf.seek(BucketsConstant.BUCKET_META_3_OBJECTS_NUMBER_POS);
            int objectNumber = raf.readInt();
            raf.seek(BucketsConstant.BUCKET_META_3_OBJECTS_NUMBER_POS);
            raf.writeInt(objectNumber + 1);
        }
    }

    public static void addObjectToLocalBucketMeta(String bucketName, String objectPath) throws IOException {
        File file = new File(BucketsConstant.BUCKET_META_PREFIX_PATH + bucketName + BucketsConstant.BUCKET_META_ALONE_FILE_SUFFIX_PATH);
        // 追加数据到文件
        FileOutputStream fo = new FileOutputStream(file, true);
        // 获取起始索引
        long startIndex = file.length();
        try (fo) {
            // 写入对象名长度
            fo.write(objectPath.getBytes().length);
            // 写入对象名
            fo.write(objectPath.getBytes());
        }
        // 添加索引
        ObjectsIndex.addIndex(bucketName, (int) startIndex);
    }

    public static String[] getObjectPathListInLocalBucketMeta(String bucketName, int start, int len) throws IOException {
        // 读取文件
        File file = new File(BucketsConstant.BUCKET_META_PREFIX_PATH + bucketName + BucketsConstant.BUCKET_META_ALONE_FILE_SUFFIX_PATH);
        FileInputStream fi = new FileInputStream(file);
        String[] objectList = new String[len];
        int startIndex = ObjectsIndex.getIndex(bucketName, start);
        int i = 0;
        try (fi) {
            fi.skip(startIndex);
            while (i < len) {
                // 读取对象名长度
                int objectPathLength = fi.read();
                // 读取对象名
                byte[] objectPathBytes = fi.readNBytes(objectPathLength);
                objectList[i] = new String(objectPathBytes);
                i++;
            }
        }
        return objectList;
    }
}
